package api

import (
	"gin_blog/models"
	"gin_blog/pkg/app"
	"gin_blog/pkg/e"
	"gin_blog/pkg/util"
	"gin_blog/service/auth_service"
	"github.com/gin-gonic/gin"
	"golang.org/x/crypto/bcrypt"
	"net/http"
	"strings"
	"time"
)

type auth struct {
	Phone string `json:"phone" form:"phone" valid:"Required;Phone"`
	Password string `json:"password" form:"password" valid:"Required;MaxSize(50)"`
}


// @Tags 用户
// @Summary 登录
// @Produce  json
// @Param username body string true "username"
// @Param password body string true "password"
// @Success 200 {string} json "{"code":200,"data":{},"msg":"ok"}"
// @Router /login [post]
func Login(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
		form auth
	)
	httpCode,errCode :=app.BindAndValid(c,&form)
	if errCode!=e.SUCCESS{
		appG.Response(httpCode,errCode,nil)
		return
	}

	authService := auth_service.Auth{Phone: form.Phone, Password: form.Password}
	isExist, err := authService.Check()
	if err != nil {
		appG.Response(http.StatusInternalServerError, e.ERROR, nil)
		return
	}
	if !isExist {
		appG.Response(http.StatusUnauthorized, e.ERROR_NOT_USER_FAIL, nil)
		return
	}
	_, err,user := authService.IsTelephoneExist()
	//判断密码是否正确
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(form.Password)); err != nil {
		appG.Response(http.StatusUnprocessableEntity,e.ERROR_AUTH_PASSWORD_FAIL,nil)
		return
	}
	token, err := util.GenerateToken(form.Phone, form.Password)
	if err != nil {
		appG.Response(http.StatusInternalServerError, e.ERROR_AUTH_TOKEN, nil)
		return
	}

	appG.Response(http.StatusOK, e.SUCCESS, map[string]string{
		"token": token,
	})
}

// @Tags 用户
// @Summary 注册
// @Produce  json
// @Param user_name body string true "user_name"
// @Param nick_name body string true "nick_name"
// @Param phone body string true "phone"
// @Param password body string true "password"
// @Param re_password body string true "re_password"
// @Success 200 {string} json "{"code":200,"data":{},"msg":"ok"}"
// @Router /register [post]
func Register(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
		form models.Auth
	)
	httpCode, errCode := app.BindAndValid(c, &form)
	if errCode != e.SUCCESS {
		appG.Response(httpCode, errCode, nil)
		return
	}
	//密码加密
	HasedPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), bcrypt.DefaultCost)
	authService :=auth_service.Auth{Username: form.Username,Nickname: form.Nickname,Phone: form.Phone,Password: string(HasedPassword)}
	IsNicknameExist,err :=authService.IsNicknameExist()
	if IsNicknameExist{
		appG.Response(http.StatusInternalServerError, e.ERROR_REGISTER_NICKNAME_FAIL, nil)
		return
	}
	IsTelephoneExist,err,_ :=authService.IsTelephoneExist()
	if IsTelephoneExist{
		appG.Response(http.StatusInternalServerError, e.ERROR_REGISTER_PHONE_FAIL, nil)
		return
	}
	isExist :=authService.AddUser()
	if isExist!=nil {
		appG.Response(http.StatusInternalServerError, e.ERROR_REGISTER_FAIL, nil)
		return
	}
	token, err := util.GenerateToken(form.Phone, form.Password)
	if err != nil {
		appG.Response(http.StatusInternalServerError, e.ERROR_AUTH_TOKEN, nil)
		return
	}
	appG.Response(http.StatusOK,e.SUCCESS_REGISTER,gin.H{
		"token":token,
	})
}

// @Tags 用户
// @Summary 用户信息
// @Produce  json
// @Param Authorization header string true "Bearer 用户token"
// @Success 200 {string} json "{"code":200,"data":{},"msg":"ok"}"
// @Router /userinfo [get]
func UserInfo(c *gin.Context)  {
	var appG=app.Gin{C: c}

	token :=c.GetHeader("Authorization")

	if token=="" || !strings.HasPrefix(token, "Bearer "){
		appG.Response(http.StatusBadRequest,e.INVALID_PARAMS,nil)
		return
	}
	claims,err :=util.ParseToken(token[7:])
	if err!=nil{
		appG.Response(http.StatusOK,e.ERROR_AUTH_CHECK_TOKEN_FAIL,nil)
		return
	}
	if time.Now().Unix()>claims.ExpiresAt{
		appG.Response(http.StatusOK,e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT,nil)
		return
	}

	authService :=auth_service.Auth{Phone:claims.Phone}
	userinfo,err :=authService.GetUser()
	if err != nil {
		appG.Response(http.StatusOK, e.ERROR_EXIST_USER_FAIL, claims)
		return
	}

	appG.Response(http.StatusOK,e.SUCCESS,map[string]interface{}{
		"username":userinfo.Username,
		"nickname":userinfo.Nickname,
		"avatar":userinfo.Avatar,
		"phone":userinfo.Phone,
	})
}
